#pragma once

#include "Declaration.h"

#include <memory>
#include <stack>
#include <vector>

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdocumentation"

#include "include/core/SkColorFilter.h"
#include "include/core/SkImageFilter.h"
#include "include/core/SkMaskFilter.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPathEffect.h"
#include "include/core/SkShader.h"
#include "include/effects/SkImageFilters.h"

#pragma clang diagnostic pop

namespace RNSkia {
class DeclarationContext {
public:
    DeclarationContext()
    {
        save();
    }
    ~DeclarationContext()
    {
        restore();
    }

    Declaration<sk_sp<SkShader>> *getShaders()
    {
        return &_shaders.top();
    }
    ComposableDeclaration<sk_sp<SkImageFilter>> *getImageFilters()
    {
        return &_imageFilters.top();
    }
    ComposableDeclaration<sk_sp<SkColorFilter>> *getColorFilters()
    {
        return &_colorFilters.top();
    }
    ComposableDeclaration<sk_sp<SkPathEffect>> *getPathEffects()
    {
        return &_pathEffects.top();
    }
    Declaration<sk_sp<SkMaskFilter>> *getMaskFilters()
    {
        return &_maskFilters.top();
    }
    Declaration<std::shared_ptr<SkPaint>> *getPaints()
    {
        return &_paints.top();
    }

    void save()
    {
        _paints.emplace();
        _shaders.emplace();
        _imageFilters.emplace([](sk_sp<SkImageFilter> inner, sk_sp<SkImageFilter> outer) {
            return SkImageFilters::Compose(outer, inner);
        });
        _colorFilters.emplace([](sk_sp<SkColorFilter> inner, sk_sp<SkColorFilter> outer) {
            return SkColorFilters::Compose(outer, inner);
        });
        _pathEffects.emplace([](sk_sp<SkPathEffect> inner, sk_sp<SkPathEffect> outer) {
            return SkPathEffect::MakeCompose(outer, inner);
        });
        _maskFilters.emplace();
    }

    void restore()
    {
        _shaders.pop();
        _imageFilters.pop();
        _colorFilters.pop();
        _pathEffects.pop();
        _maskFilters.pop();
        _paints.pop();
    }

private:
    std::stack<Declaration<sk_sp<SkShader>>> _shaders;
    std::stack<ComposableDeclaration<sk_sp<SkImageFilter>>> _imageFilters;
    std::stack<ComposableDeclaration<sk_sp<SkColorFilter>>> _colorFilters;
    std::stack<ComposableDeclaration<sk_sp<SkPathEffect>>> _pathEffects;
    std::stack<Declaration<sk_sp<SkMaskFilter>>> _maskFilters;
    std::stack<Declaration<std::shared_ptr<SkPaint>>> _paints;
};
} // namespace RNSkia
